{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 一.原理介绍\n",
    "这一节介绍基于密度聚类的代表DBSCAN（Density-Based Spatial Clustering of Applications with Noise）,它的思路也很直观自然，即将高密度聚集的样本看做一个簇，定义高密度，必然要考虑两个指标：   \n",
    "\n",
    "（1）距离：只有距离近才有可能形成高密度区域；   \n",
    "\n",
    "（2）数量：只有样本达到一定的量才有意义，比如两个点虽然相距很近，但说这两个点是高密度区域确有些迁强；   \n",
    "\n",
    "所以，DBSCAN定义了两个超参数$(\\epsilon,min\\_sample)$对簇做约束：$\\epsilon$用于控制距离，$min\\_sample$用于控制数量，然后在此超参数的基础上，我们进一步定义另外几个概念，方便我们后续的算法推导，假设我们有样本$D={x_1,x_2,...,_m}$\n",
    "\n",
    "#### $\\epsilon-$领域\n",
    "对$x_j\\in D$，其$\\epsilon-$领域表示与其距离在$\\epsilon$内的其他样本点所组成的集合，表示为$N_{\\epsilon}(x_j)=\\{x_i\\in D\\mid dist(x_i,x_j)\\leq \\epsilon\\}$\n",
    "#### 核心对象\n",
    "若样本点的$\\epsilon-$领域至少包含$min\\_sample$，即$\\left|N_{\\epsilon}(x_j)\\right|\\geq min\\_sample$，则该样本$x_j$就是一个核心对象\n",
    "#### 密度直达\n",
    "若$x_j$位于$x_i$的$\\epsilon-$领域内，且$x_i$是核心对象，则称$x_j$由$x_i$密度直达（注意有两个前提条件）\n",
    "#### 密度可达\n",
    "若存在样本序列$x_{q_1},x_{q_2},...,x_{q_k}$，使得如下关系存在   \n",
    "\n",
    "$$\n",
    "x_i\\rightarrow x_{q_1}\\rightarrow x_{q_2}\\rightarrow\\cdots \\rightarrow x_{q_k}\\rightarrow x_j\n",
    "$$  \n",
    "\n",
    "其中，$x_p\\rightarrow x_q$表示$x_q$由$x_p$密度直达，那么称$x_j$由$x_i$密度可达\n",
    "\n",
    "#### 密度相连\n",
    "对$x_i$与$x_j$，若存在$x_k$使得$x_i$与$x_j$均由$x_k$密度可达，则称$x_i$与$x_j$密度相连\n",
    "\n",
    "如下图，虚线表示$\\epsilon-$领域，$x_1$是核心对象（$min\\_sample=3$），$x_2$由$x_1$密度直达，$x_3$由$x_1$密度可到，$x_3$与$x_4$密度相连\n",
    "![avatar](./source/18_聚类_DBSCAN1.png)\n",
    "\n",
    "那么，基于这些定义如何去造一个簇呢？DBSCAN的定义是：由密度可达关系导出的最大的密度相连样本集合。这句话读起来拗口，翻译成直白话就是：   \n",
    "\n",
    "**以核心对象为圆心，$\\epsilon$为半径(欧氏距离)，画一个超圆，若超圆内的其他点也是核心对象，那么继续以该点为圆心，$\\epsilon$为半径画超圆,...,直到画不动为止，所有这些超圆内的样本点组成一个簇**  \n",
    "\n",
    "于是，DBSCAN的思路差不多就有了：   \n",
    "\n",
    "（1）找出所有的核心节点；   \n",
    "\n",
    "（2）随机挑一个核心节点，画超圆...画....画...，组成第一个簇（注意：这个簇内还可能包含有其他的核心节点），然后从剩下的核心节点（不在第一个簇中）再随机挑选一个核心节点画超圆...组成第二簇，重复该步骤，直到没有核心节点\n",
    "\n",
    "需要注意一点的就是，可能存在不在所有簇中的样本点，显然这样的样本点离其他的样本点距离都较远，所以我们可以将这样的点看做是离群点或者异常点"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 二.算法流程\n",
    "\n",
    ">输入：样本集$D=\\{x_1,x_2,...,x_m\\}$，领域参数$(\\epsilon,min\\_sample)$；  \n",
    "\n",
    ">过程：  \n",
    "\n",
    ">（1）初始化核心对象集合$H=\\{\\}$  \n",
    "\n",
    ">（2）对$j=1,2,...,m$\n",
    ">> 如果$\\left|N_{\\epsilon}(x_j)\\right|\\geq min\\_sample$，那么$H=H\\bigcup \\{x_j\\}$  \n",
    "\n",
    ">（3）初始化聚类簇数$k=0$  \n",
    "\n",
    ">（4）初始化未访问样本集合$W=D$  \n",
    "\n",
    ">（5）while $H\\neq \\{\\}$  \n",
    "\n",
    ">> （5.1）记录当前未访问样本集合$W_{old}=W$  \n",
    "\n",
    ">> （5.2）随机选择一个核心对象$o\\in H$，初始化队列$Q=<o>$  \n",
    "\n",
    ">> （5.3）$W=W/ \\{o\\}$   \n",
    "\n",
    ">> （5.4）while $Q\\neq <>$  \n",
    "\n",
    ">>> （5.4.1）取出队列$Q$中的首个样本$q$；   \n",
    "\n",
    ">>> （5.4.2）如果$\\left|N_{\\epsilon}(q)\\right|\\geq min\\_sample$，则：   \n",
    "\n",
    ">>>> 令$\\Delta=\\left|N_{\\epsilon}(q)\\right|\\bigcap W$   \n",
    "\n",
    ">>>> 将$\\Delta$中的样本加入队列$Q$；  \n",
    "\n",
    ">>>> $W=W/\\Delta$   \n",
    "\n",
    ">> （5.5）$k=k+1$，生成聚类簇$C_k=W_{old}/W$；   \n",
    "\n",
    ">> （5.6）$H=H/C_k$   \n",
    "\n",
    ">输出，簇划分$C=\\{C_1,C_2,...,C_k\\}$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 三.代码实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "DBSCAN密度聚类的代码实现，封装到ml_models.cluster\n",
    "\"\"\"\n",
    "import numpy as np\n",
    "from queue import Queue\n",
    "\n",
    "\n",
    "class DBSCAN(object):\n",
    "    def __init__(self, eps=0.5, min_sample=3, dist_method=None):\n",
    "        \"\"\"\n",
    "        :param eps:epsilon领域半径\n",
    "        :param min_sample: 核心对象的epsilon领域半径内的最少样本量\n",
    "        :param dist_method:样本距离度量，默认欧氏距离\n",
    "        \"\"\"\n",
    "        self.eps = eps\n",
    "        self.min_sample = min_sample\n",
    "        self.dist_method = dist_method\n",
    "        if self.dist_method is None:\n",
    "            self.dist_method = lambda x, y: np.sqrt(np.sum(np.power(x - y, 2)))\n",
    "        self.label_ = None  # 记录样本标签，-1表示异常点\n",
    "\n",
    "    def fit(self, X):\n",
    "        rows = X.shape[0]\n",
    "        self.label_ = np.ones(rows) * -1\n",
    "        M = np.zeros(shape=(rows, rows))\n",
    "        # 计算样本间的距离\n",
    "        for i in range(rows - 1):\n",
    "            for j in range(i, rows):\n",
    "                M[i, j] = self.dist_method(X[i], X[j])\n",
    "                M[j, i] = M[i, j]\n",
    "        # 记录核心矩阵\n",
    "        H = set()\n",
    "        for i in range(0, rows):\n",
    "            if np.sum(M[i] <= self.eps) >= self.min_sample:\n",
    "                H.add(i)\n",
    "        # 初始化聚类簇数\n",
    "        k = 0\n",
    "        # 初始化未访问样本集合\n",
    "        W = set(range(rows))\n",
    "        while len(H) > 0:\n",
    "            # 记录当前未访问样本集合\n",
    "            W_old = W.copy()\n",
    "            # 随机选择一个核心对象\n",
    "            o = np.random.choice(list(H))\n",
    "            # 初始化队列\n",
    "            Q = Queue()\n",
    "            Q.put(o)\n",
    "            # 未访问队列中去掉核心对象o\n",
    "            W = W - set([o])\n",
    "            while not Q.empty():\n",
    "                # 取出首个样本\n",
    "                q = Q.get()\n",
    "                # 判断是否为核心对象\n",
    "                if q in H:\n",
    "                    # 获取领域内样本与未访问样本的交集\n",
    "                    delta = set(np.argwhere(M[q] <= self.eps).reshape(-1).tolist()) & W\n",
    "                    # 将其放入队列\n",
    "                    for d in delta:\n",
    "                        Q.put(d)\n",
    "                    # 从未访问集合中去掉\n",
    "                    W = W - delta\n",
    "            # 获取聚类簇idx\n",
    "            C_k = W_old - W\n",
    "            k_idx = list(C_k)\n",
    "            self.label_[k_idx] = k\n",
    "            k += 1\n",
    "            # 去掉在当前簇中的核心对象\n",
    "            H = H - C_k\n",
    "\n",
    "    def fit_predict(self, X):\n",
    "        self.fit(X)\n",
    "        return self.label_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 四.测试"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn import datasets\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "#造伪数据\n",
    "X, _ = datasets.make_moons(noise=0.01)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "#训练\n",
    "dbscan = DBSCAN(eps=0.2, min_sample=3)\n",
    "lable = dbscan.fit_predict(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1f7c6724dd8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.scatter(X[:, 0], X[:, 1], c=lable)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
